﻿using System.Diagnostics;
using System.Reflection;
using System.Text;

namespace K9Nano.Updater.Extensions;

public static class ExceptionExtensions
{
    public static string ToFriendlyMessage(this Exception ex)
    {
        var sb = new StringBuilder();
        GetExceptionDetailsInternal(ex, sb);
        return sb.ToString();
    }

    static void GetExceptionDetailsInternal(Exception ex, StringBuilder sb, int indentLevel = 0)
    {
        string indent = new string(' ', indentLevel * 2);

        sb.AppendLine($"{indent}Error: {ex.Message}");
        sb.AppendLine($"{indent}Type: {ex.GetType().FullName}");
        sb.AppendLine($"{indent}Stack Trace:");

        var stackTrace = new StackTrace(ex, true);
        var filteredFrames = stackTrace.GetFrames()
            ?.Where(frame => !IsSystemAssembly(frame.GetMethod()?.DeclaringType?.Assembly))
            .ToList();

        if (filteredFrames != null && filteredFrames.Count != 0)
        {
            foreach (var frame in filteredFrames)
            {
                sb.AppendLine($"{indent}  at {frame.GetMethod()?.DeclaringType?.FullName}.{frame.GetMethod()?.Name} in {frame.GetFileName()}:line {frame.GetFileLineNumber()}");
            }
        }
        else
        {
            sb.AppendLine($"{indent}  No stack trace available.");
        }

        if (ex.InnerException != null)
        {
            sb.AppendLine($"{indent}Inner Exception:");
            GetExceptionDetailsInternal(ex.InnerException, sb, indentLevel + 1);
        }

        if (ex is AggregateException aggEx)
        {
            sb.AppendLine($"{indent}Aggregate Exception Inner Exceptions:");
            foreach (var innerEx in aggEx.InnerExceptions)
            {
                GetExceptionDetailsInternal(innerEx, sb, indentLevel + 1);
            }
        }
    }

    // 判断程序集是否为系统程序集
    static bool IsSystemAssembly(Assembly? assembly)
    {
        if (assembly == null) return false;
        var assemblyName = assembly.GetName().Name;
        if (assemblyName == null) return false;
        // 根据程序集名称前缀过滤
        return assemblyName.StartsWith("System.", StringComparison.Ordinal)
               || assemblyName.StartsWith("Microsoft.", StringComparison.Ordinal)
               || assemblyName.StartsWith("netstandard", StringComparison.Ordinal)
               || assemblyName.StartsWith("WindowsBase", StringComparison.Ordinal)
               || assemblyName.StartsWith("mscorlib", StringComparison.Ordinal);
    }
}
